﻿/*
 * Copyright (c) <2012> <guangboo49@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this 
 * software and associated documentation files (the "Software"), to deal in the Software 
 * without restriction, including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
 * to whom the Software is furnished to do so, subject to the following conditions: 
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace Optparse {
    internal static class FormatUtil {
        public static string Justify(this string self, int width) {
            int len = self.Length;
            if (len < width) {
                int left = (width - len) / 2;
                return self.PadLeft(left + len);
            } else if (len == width) {
                return self;
            } else {
                StringBuilder sb = new StringBuilder(width);
                int startIndex = 0;
                while (true) {
                    string substr = self.Substring(startIndex, width);
                    if (substr.Length < width) {
                        sb.AppendFormat("{0}", substr.Justify(width));
                        break;
                    } else {
                        sb.AppendFormat("{0}\n", substr);
                        startIndex += width;
                    }
                }
                return sb.ToString();
            }
        }

        internal static string PadLeft(this string self, int width, int left) {
            int len = self.Length;
            if (len <= width) {
                return self;
            } else {
                StringBuilder sb = new StringBuilder(width);
                LineBuffer lb = new LineBuffer(self, width);
                string line;
                if (lb.Pop(out line)) {
                    sb.AppendFormat("{0}", line);

                    while (lb.Pop(out line)) {
                        sb.AppendFormat("\n{0}", line.PadLeft(left + line.Length));
                    }
                }
                return sb.ToString();
            }
        }

        private class LineBuffer {
            private string raw;
            private int bufferwidth;
            private int index;
            private int total;

            public LineBuffer(string str, int width) {
                raw = str;
                bufferwidth = width;
                index = 0;
                total = str.Length;
            }

            public bool Pop(out string line) {
                if (index >= total) {
                    line = string.Empty;
                    return false;
                }

                if (index + bufferwidth < total) {
                    int end = index + bufferwidth - 1;
                    // has newline
                    int li = raw.IndexOf('\n', index, bufferwidth);

                    if (li > 0) {
                        line = raw.Substring(index, li - index);
                        index = li + 1;
                        return true;
                    }

                    if (raw[end] == ' ') {
                        line = raw.Substring(index, bufferwidth);
                        index = end + 1;
                        return true;
                    } else {
                        li = raw.LastIndexOf(' ', end, bufferwidth);
                        if (li < 0) {
                            line = raw.Substring(index, bufferwidth - 1) + "-";
                            index = end;
                            return true;
                        } else {
                            line = raw.Substring(index, li - index + 1);
                            index = li + 1;
                            return true;
                        }
                    }
                } else {
                    line = raw.Substring(index, total - index);
                    index = total;
                    return true;
                }
            }
        }

        private static readonly Regex _aliasRegex = new Regex(@"^\-[\d\w]{1,2}$", RegexOptions.Compiled);
        private static readonly Regex _nameRegex = new Regex(@"^\-\-[\d\w]{2,10}$", RegexOptions.Compiled);

        public static bool ValidateAlias(string alias) { return _aliasRegex.IsMatch(alias); }
        public static bool ValidateName(string name) { return _nameRegex.IsMatch(name); }
    }
}
